package server

import (
	"context"
	"errors"
	"fmt"
	global2 "longmen/server/config/global"
	"longmen/server/pkg/common/helper/const"
	"longmen/server/pkg/common/helper/encrypt"
	time2 "longmen/server/pkg/common/helper/timehelper"
	"longmen/server/pkg/common/helper/util"
	"longmen/server/pkg/db/mysql"
	"longmen/server/pkg/db/mysql/db_main"
	"longmen/server/pkg/db/mysql/models/models_main"
	"longmen/server/pkg/db/redis/cache"
	pb "longmen/server/pkg/protobuf"
	"time"

	"longmen/server/pkg/common/api_models"
)

// 用户登录,移动端用手机+验证码登录时,如果手机未注册,则注册(相当于注册第一步,Regist方法).
func (s *Server) Login(ctx context.Context, req *pb.LoginReq) (*pb.LoginResp, error) {
	var user *models_main.User
	var err error

	//check User Status
	//此处多次重复查数据库，需要确认有没有对account和mobile加索引
	_, err = s.CheckUserStatus(&api_models.LoginReq{Account: req.GetAccount(), LoginType: int(req.LoginType)})
	if err != nil {
		return nil, err
	}
	if req.LoginType == 1 {
		user, err = s.GetUserByAccountAndPwd(&api_models.LoginReq{Account: req.GetAccount(), Pwd: req.GetPwd()})
		if err != nil || user.Id <= 0 {
			n, err := s.WrongPasswordCounter(&api_models.LoginReq{Account: req.GetAccount(), LoginType: int(req.LoginType)})
			global2.Log.Infof("6Account9账号或密码错误,累计%d次", n)
			return nil, err
		}
	} else {
		err = util.CheckMobile(req.GetAccount())
		if err != nil {
			return nil, err
		}
		err := s.CheckCode(req.GetAccount(), req.GetPwd())
		if err != nil {
			n, err := s.WrongPasswordCounter(&api_models.LoginReq{Account: req.GetAccount(), LoginType: int(req.LoginType)})
			if n != 0 {
				global2.Log.Infof("6Account9:用户%s手机登陆失败%v", req.GetAccount(), err)
			}
			return nil, err
		}
		user, err = s.GetUser(map[string]interface{}{"mobile": req.Account})
		if err != nil {
			return nil, err
		}
		if user.Id == 0 {
			/*if req.Platform == 0 {
				return nil, errors.New("手机号未注册")
			}*/
			mobileHash := encrypt.GenHashWithLength(11) //进入手机直接注册模式
			rHash := cache.GetMobileToHash(req.Account)
			if len(rHash) > 1 {
				err := cache.DelRegisterVerify(rHash)
				if err != nil {
					return nil, err
				}
			}
			err = cache.SetRegisterVerify(mobileHash, req.Account)
			if err != nil {
				return nil, err
			}
			return &pb.LoginResp{MobileHash: mobileHash}, nil
		}
	}
	return s.GenLoginResp(user, LoginParam{
		SourceKey:  req.SourceKey,
		SourceId:   req.SourceId,
		Website:    req.Website,
		Platform:   req.Platform,
		Ip:         req.GetIp(),
		DeviceInfo: req.DeviceInfo,
	})
}

//先认定用户输入的是手机号+密码登录,如果查不到则把他的用户名认定为账号名.

//复杂情况：输入的用户名，与某账号名和手机号重合,这种情况不是特殊,有很多,因为有人喜欢用手机号设置为账号名.

//账号名与手机号相同却不是同一账号的情况:有人更换了手机号绑定,账号名却没更改.或者在设置账号名时设置错了自己的手机号

//哪个对登录哪个,如果账户名的密码对,提示他绑定他的手机号

// 如果两个都对,登录手机号的,提示他有另一账号名与他手机号相同(不能提示密码一模一样),提示他如果是本人账号,请他去往那个账号绑定手机号,如果不是,请他更改密码.
func (s *Server) GetUserByAccountAndPwd(req *api_models.LoginReq) (*models_main.User, error) {
	//(手机号+密码) 优先级大于 (账号名+密码)
	//先判断用户输入的是手机号+密码登录
	var result *models_main.User
	var err error
	var account = ""
	errMobile := util.CheckMobile(req.Account)
	if errMobile == nil { //如果他是手机号

		//用户输入的账号名是否匹配手机号正则
		//手机号+密码登录
		account, err = db_main.GetUserAccountByMobile(req.Account)
		if err != nil {
			return nil, err
		}
		if account != "" {
			//查到他的手机号对应的账号名,用账号名+密码登录
			password, err := encrypt.PwdDesECBEncrypt(account, req.Pwd)
			if err != nil {
				return nil, err
			}
			condition := make(map[string]interface{})
			condition["account"] = account
			condition["password"] = password
			result, err := mysql.GetUserParam(condition)
			if err != nil {
				return nil, err
			}
			return result, nil
		}
	}
	//账号名+密码登录
	password, err := encrypt.PwdDesECBEncrypt(req.Account, req.Pwd)
	if err != nil {
		return nil, err
	}

	condition := make(map[string]interface{})
	condition["account"] = req.Account
	condition["password"] = password
	result, err = mysql.GetUserParam(condition)
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (s *Server) GetUser(param map[string]interface{}) (*models_main.User, error) {
	return mysql.GetUserParam(param)
}

func (s *Server) UpdateUserLoginInfo(user *models_main.User, loginPlatform int) (string, error) {
	token, err := encrypt.TokenWebDesECBEncrypt()
	if err != nil {
		return "", err
	}
	//更改登陆token
	if loginPlatform == _const.LOGIN_PLATFORM_WEB {
		user.TokenWeb = token
	} else {
		user.Token = token
	}
	user.LastLogin = time.Now().In(time2.GetLocalLocation())
	user.LoginPlatform = loginPlatform

	err = db_main.UpdateUser([]string{"last_login", "login_platform",
		"last_ip", "token", "token_web", "online_status", "banned_num", "login_source_id"}, user)
	if err != nil {
		return "", err
	}
	return token, nil
}

func (s *Server) WrongPasswordCounter(req *api_models.LoginReq) (int, error) {
	var result *models_main.User
	var err error
	account := req.Account
	bPhone := (req.LoginType == 2)
	sMsg := global2.Lang.T("user_or_pass_err")

	if bPhone {
		//手机号+密码登录
		sMsg = global2.Lang.T("verification_code_err")
	}
	errMobile := util.CheckMobile(account)
	if errMobile == nil { //是手机号，要先取一下account
		account, err = db_main.GetUserAccountByMobile(req.Account)
		if err != nil || account == "" {
			return 0, errors.New(fmt.Sprintf("%s", sMsg))
		}
	}
	////////////////
	result, err = db_main.GetUserAccountByName(account)
	if err != nil {
		return 0, err
	}
	if result.BannedNum >= 10 {
		result.Status = _const.ACCOUNT_STATUS_TMP_BANNED
		err = errors.New(global2.Lang.T("login_blocked"))
		result.BlockUntilTime = time.Now().Add(time.Hour * 24)
	} else {
		result.BannedNum += 1
		if result.Id != 0 {
			err = errors.New(fmt.Sprintf(global2.Lang.T("verification_cumulative_err"), sMsg, result.BannedNum))
		} else {
			err = errors.New(fmt.Sprintf("%s", sMsg))
		}

	}
	if result.Id != 0 {
		errUpdate := db_main.UpdateUser([]string{"banned_num", "status", "block_until_time"}, result)
		if errUpdate != nil {
			global2.Log.Errorf("6Login9%v", errUpdate)
		}
	}
	return result.BannedNum, err
}

/*
Enzo July 11 2022
只有在用户被封禁时才报错
*/
func (s *Server) CheckUserStatus(req *api_models.LoginReq) (int, error) {
	var err error
	var user *models_main.User

	if errMobile := util.CheckMobile(req.Account); errMobile == nil { //is number
		user, err = db_main.GetUserByMobile(req.Account)
		if err != nil {
			global2.Log.Infof("6Account9Login用户用手机登陆但没有对应的账号:%v", err)
			return 0, nil
		}
	} else {
		user, err = db_main.GetUserAccountByName(req.Account)
		if err != nil {
			return 0, nil
		}
	}

	if user.Status == _const.ACCOUNT_STATUS_BANNED { //被封禁
		return 0, errors.New(util.MSG_LOGIN_BANNED)
	}
	if user.Status == _const.ACCOUNT_DEACTIVED && user.DeactiveTime.Before(time.Now()) { //注销时间已到
		return 0, errors.New(util.MSG_LOGIN_DEACTIVED)
	}
	if user.Status == _const.ACCOUNT_STATUS_TMP_BANNED ||
		user.Status == _const.ACCOUNT_STATUS_KICKED_OUT {
		if time.Now().After(user.BlockUntilTime) { //解封
			user.BannedNum = 0
			user.Status = _const.ACCOUNT_STATUS_NORMAL
			db_main.UpdateUser([]string{"banned_num", "status"}, user)
		} else {
			statusErrorMsg := global2.Lang.T("login_blocked")
			if user.Status == _const.ACCOUNT_STATUS_KICKED_OUT {
				statusErrorMsg = util.MSG_LOGIN_KICKED_OUT
			}
			return 0, errors.New(statusErrorMsg)
		}
	}
	return user.Status, nil //状态正常
}

/*
@Create July07 2022 Enzo
根据请求信息和登陆信息，生成一条记录
*
*/
func GenUserLog(u *models_main.User, r *api_models.LoginReq, deviceInfo string) error {
	uLog := &models_main.UserLog{
		Uid:           u.Id,
		CreateTime:    u.LastLogin,
		IsAnchor:      uint8(u.IsAnchor),
		Guild:         u.GuildId,
		LastIp:        r.Ip,
		LoginPlatform: uint8(r.LoginPlatform),
		LoginSourceId: fmt.Sprint(r.SourceId), //登陆来源
		Device:        deviceInfo,
	}
	//err := cache.PushAny(uLog, util.AccountUserLogChannel)
	err := global2.PublisherAccount.Send(uLog)

	return err

}
